package service.common;

import database.app.PersonDao;
import model.app.Person;
import model.common.AttributeValue;

import static service.CustomProtocol.*;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.transform.stream.StreamSource;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringReader;
import java.util.List;

public class ResourcesServlet extends HttpServlet {
    private static final int MIN_XML_LENGTH=1;

    @Override
    public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        long startTime=System.currentTimeMillis();
        String requestedResource = request.getParameter("resource");
        PrintWriter out = response.getWriter();
        out.println(XML_VERSION);
        out.println(SERVICE_START);

        if(requestedResource==null || requestedResource.trim().length()<1){
            out.println(STATUS_START);
            out.println(BAD_REQUEST);
            out.println(BAD_REQUEST_DEFAULT_MESSAGE);
            out.println(STATUS_STOP);
            out.println(SERVICE_STOP);
            return;
        }

        switch (requestedResource.toLowerCase())
        {
            case "organigram" :
            {
                String root=request.getParameter("root");
                if(root==null){
                    out.println(STATUS_START);
                    out.println(BAD_REQUEST);
                    out.println(BAD_REQUEST_DEFAULT_MESSAGE);
                    out.println(STATUS_STOP);
                    out.println(SERVICE_STOP);
                    break;
                }
                Department department= DepartmentDao.getOrganigram(root,0);
                if(department == null){
                    out.println(STATUS_START);
                    out.println(NO_CONTENT);
                    out.println(NO_CONTENT_DEFAULT_MESSAGE);
                    out.println(STATUS_STOP);
                    out.println(SERVICE_STOP);
                    break;
                }

                try {
                    out.println(STATUS_START);
                    out.println(STATUS_OK);
                    out.println(STATUS_STOP);
                    out.println(RESPONSE_START);
                    JAXBContext context = JAXBContext.newInstance(Department.class);
                    Marshaller m = context.createMarshaller();
                    m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
                    m.setProperty(Marshaller.JAXB_FRAGMENT, Boolean.TRUE);
                    m.marshal(department,out);
                    out.println(RESPONSE_STOP);
                    out.println(SERVICE_STOP);
                } catch (JAXBException e) {
                    e.printStackTrace();
                }
                break;
            }

            case "department" :
            {
                String depId=request.getParameter("id");
                if(depId==null){
                    out.println(STATUS_START);
                    out.println(BAD_REQUEST);
                    out.println(BAD_REQUEST_DEFAULT_MESSAGE);
                    out.println(STATUS_STOP);
                    out.println(SERVICE_STOP);
                    break;
                }
                Department department= DepartmentDao.getSingleDepartment(depId);
                if(department == null){
                    out.println(STATUS_START);
                    out.println(NO_CONTENT);
                    out.println(NO_CONTENT_DEFAULT_MESSAGE);
                    out.println(STATUS_STOP);
                    out.println(SERVICE_STOP);
                    break;
                }

                try {
                    out.println(STATUS_START);
                    out.println(STATUS_OK);
                    out.println(STATUS_STOP);
                    out.println(RESPONSE_START);
                    JAXBContext context = JAXBContext.newInstance(Department.class);
                    Marshaller m = context.createMarshaller();
                    m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
                    m.setProperty(Marshaller.JAXB_FRAGMENT, Boolean.TRUE);
                    m.marshal(department,out);
                    out.println(RESPONSE_STOP);
                    out.println(SERVICE_STOP);
                } catch (JAXBException e) {
                    e.printStackTrace();
                }
                break;
            }


            case "person" :
            {
                String pId=request.getParameter("id");
                if(pId==null){
                    out.println(STATUS_START);
                    out.println(BAD_REQUEST);
                    out.println(BAD_REQUEST_DEFAULT_MESSAGE);
                    out.println(STATUS_STOP);
                    out.println(SERVICE_STOP);
                    break;
                }
                Person person= PersonDao.getSinglePerson(pId);
                if(person == null){
                    out.println(STATUS_START);
                    out.println(NO_CONTENT);
                    out.println(NO_CONTENT_DEFAULT_MESSAGE);
                    out.println(STATUS_STOP);
                    out.println(SERVICE_STOP);
                    break;
                }

                try {
                    out.println(STATUS_START);
                    out.println(STATUS_OK);
                    out.println(STATUS_STOP);
                    out.println(RESPONSE_START);
                    JAXBContext context = JAXBContext.newInstance(Person.class);
                    Marshaller m = context.createMarshaller();
                    m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
                    m.setProperty(Marshaller.JAXB_FRAGMENT, Boolean.TRUE);
                    m.marshal(person,out);
                    out.println(RESPONSE_STOP);
                    out.println(SERVICE_STOP);
                } catch (JAXBException e) {
                    e.printStackTrace();
                    out.println(STATUS_STOP);
                    out.println(STATUS_START);
                    out.println(SERVER_ERROR);
                    out.println(STATUS_STOP);
                    out.println(SERVICE_STOP);
                }
                break;
            }

            case "listperson" :
            {
                String emri = request.getParameter("emri");
                String mbiemri= request.getParameter("mbiemri");
                String xmlResult = PersonDao.getListPersonLikeXML(emri!=null?emri:"",mbiemri!=null?mbiemri:"");
                if (xmlResult== null || xmlResult.length()<MIN_XML_LENGTH){
                    out.println(STATUS_START);
                    out.println(NO_CONTENT);
                    out.println(NO_CONTENT_DEFAULT_MESSAGE);
                    out.println(STATUS_STOP);
                    out.println(SERVICE_STOP);
                    break;
                }
                out.println(STATUS_START);
                out.println(STATUS_OK);
                out.println(STATUS_STOP);
                out.println(RESPONSE_START);
                out.println(xmlResult);
                out.println(RESPONSE_STOP);
                out.println(SERVICE_STOP);
                break;
            }



            case "objectdetails" :
            {
                String id=request.getParameter("id");
                if(id==null){
                    out.println(STATUS_START);
                    out.println(BAD_REQUEST);
                    out.println(BAD_REQUEST_DEFAULT_MESSAGE);
                    out.println(STATUS_STOP);
                    out.println(SERVICE_STOP);
                    break;
                }
                List<AttributeValue> editionEavs= GenericDb.getObjectEAVs(id);

                if(editionEavs == null || editionEavs.size()<1){
                    out.println(STATUS_START);
                    out.println(NO_CONTENT);
                    out.println(NO_CONTENT_DEFAULT_MESSAGE);
                    out.println(STATUS_STOP);
                    out.println(SERVICE_STOP);
                    break;
                }

                try {
                    out.println(STATUS_START);
                    out.println(STATUS_OK);
                    out.println(STATUS_STOP);
                    out.println(RESPONSE_START);
                    JAXBContext context = JAXBContext.newInstance(AttributeValue.class);
                    Marshaller m = context.createMarshaller();
                    m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
                    m.setProperty(Marshaller.JAXB_FRAGMENT, Boolean.TRUE);
                    out.println("<details>");
                    for (AttributeValue eav:editionEavs){
                        m.marshal(eav,out);
                    }
                    out.println("</details>");
                    out.println(RESPONSE_STOP);
                    out.println(SERVICE_STOP);
                } catch (JAXBException e) {
                    e.printStackTrace();
                    out.println(RESPONSE_STOP);
                    out.println(STATUS_START);
                    out.println(SERVER_ERROR);
                    out.println(SERVER_ERROR_DEFAULT_MESSAGE);
                    out.println(STATUS_STOP);
                    out.println(SERVICE_STOP);
                }
                break;
            }

            default:
            {
                out.println(STATUS_START);
                out.println(NOT_IMPLEMENTED);
                out.println(NOT_IMPLEMENTED_DEFAULT_MESSAGE);
                out.println(STATUS_STOP);
                out.println(SERVICE_STOP);
            }
        }
        System.out.println("Time Served: "+requestedResource+": "+(System.currentTimeMillis()-startTime));
    }


    @Override
    public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        long startTime=System.currentTimeMillis();
        PrintWriter out = response.getWriter();

        out.println(XML_VERSION);
        out.println(SERVICE_START);

        String actionTodo = request.getParameter("action");
        if (actionTodo==null){
            out.println(STATUS_START);
            out.println(BAD_REQUEST);
            out.println(START_DETAIL+"action not specified"+STOP_DETAIL);
            out.println(STATUS_STOP);
            out.println(SERVICE_STOP);
            return;
        }
        switch (actionTodo.toLowerCase()){
            case "addattribute":
            {
                String attibuteXml = request.getParameter("attribute");
                System.out.println(attibuteXml);
                if (attibuteXml==null){
                    out.println(STATUS_START);
                    out.println(BAD_REQUEST);
                    out.println(BAD_REQUEST_DEFAULT_MESSAGE);
                    out.println(STATUS_STOP);
                    out.println(SERVICE_STOP);
                    break;
                }

                AttributeValue attribute;
                try {

                    JAXBContext jc = JAXBContext.newInstance( AttributeValue.class );
                    Unmarshaller u = jc.createUnmarshaller();
                    attribute = (AttributeValue) u.unmarshal( new StreamSource( new StringReader( attibuteXml)));
                } catch (JAXBException e) {
                    out.println(STATUS_START);
                    out.println(BAD_REQUEST);
                    out.println(START_DETAIL+"Attribute parameter must be well formatted XML"+STOP_DETAIL);
                    out.println(STATUS_STOP);
                    out.println(SERVICE_STOP);
                    e.printStackTrace();
                    break;
                }

                if (!attribute.isValid()){
                    out.println(STATUS_START);
                    out.println(BAD_REQUEST);
                    out.println(START_DETAIL+"Attribute must have at least a name"+STOP_DETAIL);
                    out.println(STATUS_STOP);
                    out.println(SERVICE_STOP);
                    break;
                }
                int rows = GenericDb.insertAttributeValue(attribute);

                if (rows < 1 ){
                    out.println(STATUS_START);
                    out.println(SERVER_ERROR);
                    out.println(START_DETAIL+"Failed to insert eav into database"+STOP_DETAIL);
                    out.println(STATUS_STOP);
                    out.println(SERVICE_STOP);
                    break;
                }

                out.println(STATUS_START);
                out.println(STATUS_OK);
                out.println(START_DETAIL+"eav inserted successfully"+STOP_DETAIL);
                out.println(STATUS_STOP);
                out.println(SERVICE_STOP);
                break;
            }

            case "updateattribute" :
            {
                String attributeXml = request.getParameter("attribute");
                String idStr = request.getParameter("id");

                if (attributeXml==null || idStr==null){
                    out.println(STATUS_START);
                    out.println(BAD_REQUEST);
                    out.println(START_DETAIL+"Missing ID(int) and/or attribute(xml)"+STOP_DETAIL);
                    out.println(STATUS_STOP);
                    out.println(SERVICE_STOP);
                    break;
                }
                int id;
                try{
                    id=Integer.parseInt(idStr);
                } catch (NumberFormatException e){
                    out.println(STATUS_START);
                    out.println(BAD_REQUEST);
                    out.println(START_DETAIL+"ID must be an integer"+STOP_DETAIL);
                    out.println(STATUS_STOP);
                    out.println(SERVICE_STOP);
                    break;
                }

                AttributeValue attribute;
                try {
                    JAXBContext jc = JAXBContext.newInstance( AttributeValue.class );
                    Unmarshaller u = jc.createUnmarshaller();
                    attribute = (AttributeValue) u.unmarshal( new StreamSource( new StringReader(attributeXml)));
                } catch (JAXBException e) {
                    out.println(STATUS_START);
                    out.println(BAD_REQUEST);
                    out.println(START_DETAIL+"attribute parameter must be well formatted XML"+STOP_DETAIL);
                    out.println(STATUS_STOP);
                    out.println(SERVICE_STOP);
                    e.printStackTrace();
                    break;
                }

                AttributeValue oldAttribute = GenericDb.getAttributeValue(id);
                if (oldAttribute==null){
                    out.println(STATUS_START);
                    out.println(BAD_REQUEST);
                    out.println(START_DETAIL+"attribute with id="+id+" does not exist"+STOP_DETAIL);
                    out.println(STATUS_STOP);
                    out.println(SERVICE_STOP);
                    break;
                }
                oldAttribute.setType(attribute.getType());
                oldAttribute.setValue(attribute.getValue());

                int rows = GenericDb.updateAttributeValue(oldAttribute);

                if (rows < 1 ){
                    out.println(STATUS_START);
                    out.println(SERVER_ERROR);
                    out.println(START_DETAIL+"Update failed to perform in database!"+STOP_DETAIL);
                    out.println(STATUS_STOP);
                    out.println(SERVICE_STOP);
                    break;
                }

                out.println(STATUS_START);
                out.println(STATUS_OK);
                out.println(START_DETAIL+"Update performed successfully: "+rows+" rows "+STOP_DETAIL);
                out.println(STATUS_STOP);
                out.println(SERVICE_STOP);
                break;
            }

            case "deleteattribute" :
            {
                String idStr = request.getParameter("id");

                if (idStr==null){
                    out.println(STATUS_START);
                    out.println(BAD_REQUEST);
                    out.println(START_DETAIL+"Missing ID(int) what to delete ?"+STOP_DETAIL);
                    out.println(STATUS_STOP);
                    out.println(SERVICE_STOP);
                    break;
                }
                int id;
                try{
                    id=Integer.parseInt(idStr);
                } catch (NumberFormatException e){
                    out.println(STATUS_START);
                    out.println(BAD_REQUEST);
                    out.println(START_DETAIL+"ID must be an integer"+STOP_DETAIL);
                    out.println(STATUS_STOP);
                    out.println(SERVICE_STOP);
                    break;
                }

                int rows = GenericDb.deleteAttribute(id);

                out.println(STATUS_START);
                out.println(STATUS_OK);
                out.println(START_DETAIL+"Rows deleted : "+rows+STOP_DETAIL);
                out.println(STATUS_STOP);
                out.println(SERVICE_STOP);
                break;
            }

            default:
            {
                out.println(STATUS_START);
                out.println(NOT_IMPLEMENTED);
                out.println(NOT_IMPLEMENTED_DEFAULT_MESSAGE);
                out.println(STATUS_STOP);
                out.println(SERVICE_STOP);
            }
        }
        System.out.println("Time job: " + actionTodo + ": " + (System.currentTimeMillis() - startTime));
    }
}
